//=============================================================================
// TF Station. Base superclass for all structures
//=============================================================================

class TFStation extends GameObjective
	placeable;

var int nearOutpost;
var travel float Health;
var float MaxHealth;
var Pawn Near;
var float Counter;
var float BuildTime;
var int MyTeam;
var int Grade;
var int chunkcount;
var sound ExplosionSound[3];
var class<gib> Chunks[4];
var string BuildingName;
var int NameIndex;
var bool directional;
var tfTeamFlare teamlight;
var float teamflareDS;
var float SkillOnDmg;

var bool isNotFresh;

var string StationName;

var Actor fx;
var class<Actor> fxClass;
var tfStationConqFX cfx;
var sound HitSounds[3];

//var Controller DelayedDamageInstigatorController;

replication
{
    reliable if( Role==ROLE_Authority )
	nearOutpost, teamlight, fx, cfx, BuildingName, Grade, MyTeam, MaxHealth, Health, Near, Counter, isNotFresh;

	reliable if ( Role < ROLE_Authority )
		upgrade, setinitialteam;
}

function PreBeginPlay()
{
    local rotator tmpRot;
    Settimer(0.1,true);
    health=maxhealth/5;
    AmbientSound=Sound'TFMedia.Buildings.tfConstructAmb';

    fx=spawn(fxclass,self);
    if(fx!=none) fx.SetBase(self);

    cfx=spawn(class'TaskForces.tfStationConqFX');
    if(cfx!=none)
    {
        cfx.station=self;
        cfx.SetBase(self);
        cfx.SetDrawScale(teamflareDS);
    }

    tmprot=rotation;
	tmprot.roll=0;

	if(!directional) tmprot.pitch=0;
	setrotation(tmprot);
    if(tfgame(level.Game)!= none && tfgame(level.Game).FastBuildTime)
        BuildTime=2.0;
}

simulated function SetInitialTeam(int t)
{
    MyTeam=t;
    defenderteamindex=byte(t);

    //CONTROL
	if(tfgri(level.game.gamereplicationinfo)!=none && nameindex!=6)
	    tfgri(level.game.gamereplicationinfo).control[myteam]+=tfgri(level.game.gamereplicationinfo).buildcost[nameindex-1];

    if(nameindex!=0)
	{
	    tfgri(level.game.gamereplicationinfo).buildingindex[myteam].index[nameindex]++;
	    buildingname=Buildingname@tfgri(level.game.gamereplicationinfo).buildingindex[myteam].index[nameindex];
    }

}

function SetDelayedDamageInstigatorController(Controller C)
{
	DelayedDamageInstigatorController = C;
}

static function float getSDM(class<DamageType> damageType)
{
    local float SDM;
    switch(damageType)
    {
    case class'DamTypeMinigunAlt':
        SDM=3;
        break;
    case class'DamTypeNKRad':
        SDM=0;
        break;
    default:
        if(class<WeaponDamageType>(damageType)!=none && class<TFWeapon>(class<WeaponDamageType>(damageType).default.WeaponClass)!=none)
            SDM = class<TFWeapon>(class<WeaponDamageType>(damageType).default.WeaponClass).default.StationDmgModifier;
        else
            SDM=1;
        break;
    }

    return SDM;
}

function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class<DamageType> damageType)
{
    local controller p;
    local playercontroller pc;
    local int num, i;
    local float tmp, factor;


    if (instigatedBy == none && DelayedDamageInstigatorController != None)
		instigatedBy = DelayedDamageInstigatorController.Pawn;

    if(instigatedby!=none && instigatedby.PlayerReplicationInfo!= none && instigatedby.PlayerReplicationInfo.Team.TeamIndex==myteam && DamageType!=class'TaskForces.DamTypeGenFlash')
        factor=tfgame(level.Game).friendlyfirescale;
    else if((damagetype==Class'Taskforces.DamTypeGuardProjR' && myteam==0) || (damagetype==Class'Taskforces.DamTypeGuardProjB' && myteam==1))
        factor=0;
    else factor=1;

    if(grade==0) factor*=2;
    factor*=getSDM(damageType);

    if( nearOutpost>0) factor/=1+(nearOutpost+1)/4;

    //factor/=tfgri(level.Game.GameReplicationInfo).getTechFactor(myteam, 0);

    tmp=damage*factor;
    damage*=factor;
    tmp-=damage;
    if(tmp<1 && frand()<tmp) tmp=1;
        damage+=tmp;

    if ( Damage > 0 )
    {
        Health -= Damage;
        health=fmax(health,0);
        isNotFresh=true;

        if(damage>0)
	    {
		    num=fmin(damage/3,20);
	        if(level.bdropdetail) num/=2;

            if(frand()*40<damage) PlaySound(HitSounds[rand(3)],,2);

            for(i=0; i<num; i++)
		    {
                //if ( EffectIsRelevant(hitlocation,false) )
	            //{
                    spawn(class'TaskForces.tfStationSparks',,,hitlocation,rotator(Normal(hitlocation - location)));
                //}
            }

	        for ( P = Level.ControllerList; P!=None; P=P.nextController )
            {
                pc=playercontroller(p);

                if(pc!=none && p.PlayerReplicationInfo.Team.TeamIndex==myteam)
                   pc.ReceiveLocalizedMessage(class'TaskForces.tfStationDmgMsg',damage,,,self);
            }
        }

        if(health<=0)
        {
		    Destructed(instigatedby, false);
	    }
    }
    if(instigatedby!=none && instigatedby.playerreplicationinfo!=none && tfpri(instigatedby.playerreplicationinfo)!=none)
    {
        if(instigatedby.playerreplicationinfo.team.teamindex==myteam)
        {
            instigatedby.playerreplicationinfo.score-=float(damage)/200;
            tfpri(instigatedby.playerreplicationinfo).SubSkill(-float(damage)/10);
        }
        else
        {
            instigatedby.playerreplicationinfo.score+=float(damage)/200;
            tfpri(instigatedby.playerreplicationinfo).AddSkill(float(damage)/10,SkillOnDmg);
        }
    }
    SkillOnDmg=0;
}

function Destructed(pawn killer, bool recycled)
{
    local controller c;
    local int i;
    local gib chunk;

	if(grade>0)
	{
		spawn(class'Taskforces.tfStationExp');
		PlaySound(explosionsound[Rand(3)],,3);

        for(i=0; i<chunkcount; i++)
		{
			chunk=spawn(chunks[rand(4)],self,,location,rotRand(true));
			if(chunk!=none) chunk.velocity=vector(rotRand(true))*(128+rand(256));
		}
	}
    else
    {
        spawn(class'TaskForces.TFFlash');
        PlaySound(sound'TFMedia.tfStationLost',,3);
    }

    if(teamlight!=none) teamlight.destroy();


    //CONTROL
    if(tfgri(level.game.gamereplicationinfo)!=none && nameindex!=6)
	    tfgri(level.game.gamereplicationinfo).control[myteam]-=tfgri(level.game.gamereplicationinfo).buildcost[nameindex-1]*fmax(1,grade);

    if(recycled && killer==none)
    {
        Destroy();
        return;
    }

    for ( c = Level.ControllerList; c!=None; c=c.nextController )
    {
        if(playercontroller(c)!=none && c.PlayerReplicationInfo.team.TeamIndex==myteam)
            playercontroller(c).ReceiveLocalizedMessage(class'TaskForces.TFLoseMsg',,killer.playerreplicationinfo,,self);
    }

    if(killer!=none && killer.PlayerReplicationInfo!=none)
    {
        if(killer.PlayerReplicationInfo.Team.TeamIndex!=myteam)
        {
            //SCORE************************
            killer.PlayerReplicationInfo.Score+=(tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*fmax(1,grade))/100;
            tfpri(killer.PlayerReplicationInfo).AddSkill((tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*fmax(1,grade))/10);
            tfpri(killer.PlayerReplicationInfo).AddRes((tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*fmax(1,grade))/10);
        }
        else //destroyed own building
        {
            //SCORE************************
            if(!recycled)
            {
                killer.PlayerReplicationInfo.Score-=(tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*fmax(1,grade))/100;
                tfpri(killer.PlayerReplicationInfo).SubSkill(-(tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*fmax(1,grade))/50);
                tfpri(killer.PlayerReplicationInfo).SubRes(-(tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*fmax(1,grade))/10);
            }
            else
            {
                //no punishment when grade==0
                killer.PlayerReplicationInfo.Score-=(tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*grade)/200;
                tfpri(killer.PlayerReplicationInfo).SubSkill(-(tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*grade)/100);

                if(grade>0) tfpri(killer.PlayerReplicationInfo).AddRes((tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1]*grade)/3);
                else tfpri(killer.PlayerReplicationInfo).AddRes((tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1])/2);
            }
        }
    }

    Destroy();
}

function Upgrade(pawn p)
{
    //CONTROL
    if(tfgri(level.game.gamereplicationinfo)!=none && nameindex!=6)
	    tfgri(level.game.gamereplicationinfo).control[myteam]+=tfgri(level.game.gamereplicationinfo).buildcost[nameindex-1];

    //SCORE************************
    p.PlayerReplicationInfo.Score+=(tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1])/200;
    tfpri(p.PlayerReplicationInfo).AddSkill((tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1])/20);

    PlaySound(sound'TFMedia.tfStationUpgrade',,256);
    spawn(class'TaskForces.TFFlash');
    grade+=1;
}

function FindNear()
{
    local pawn p;
    local controller c;

    if(near!=none && vsize(near.location-location)<196) return;

    near=none;

    for ( c = Level.ControllerList; c!=None; c=c.nextController )
    {
        p=c.Pawn;
        if(p!=none && Sentinel(p) == none && p.Health>0 && vsize(p.location-location)<196 && p.PlayerReplicationInfo!= none && p.PlayerReplicationInfo.Team.TeamIndex==myteam)
            near=p;
    }
}

function Timer()
{
    local controller c;
    local float x;
    local tfDamageSparks dmgFX;

    if(counter==0)
    {
        if(owner!=none && pawn(owner)!=none && pawn(owner).playerreplicationinfo!=none)
        {
            for ( c = Level.ControllerList; c!=None; c=c.nextController )
            {
                if(playercontroller(c)!=none && c.PlayerReplicationInfo.team != None && c.PlayerReplicationInfo.team.TeamIndex==myteam)
                    playercontroller(c).ReceiveLocalizedMessage(class'TaskForces.TFConstructMsg',,pawn(owner).playerreplicationinfo,,self);
            }
        }
    }

    if(teamlight==none)
    {
        teamlight=spawn(class'taskforces.tfteamflare');
        teamlight.setdrawscale(teamflareDS);
        teamlight.station=self;
        if(myteam==1) teamlight.texture=Shader'TFMedia.TFlareRed';
        else teamlight.texture=Shader'TFMedia.TFlareBlu';
    }

    if(nearOutpost>0) x=6;
    else x=1;

    //x*=tfgri(level.Game.GameReplicationInfo).getTechFactor(myteam, 1);


		Counter+=x;
		health+=((maxhealth*0.8)/(buildtime*10))*x;
		ambientglow=(health/maxhealth)*255;

    if(counter/10 >= buildtime)
    {
        if(cfx!=none) cfx.Destroy();

        grade=1;
        ambientglow=64;
        if(owner!=none && pawn(owner)!=none && pawn(owner).playerreplicationinfo!=none)
        {
            for ( c = Level.ControllerList; c!=None; c=c.nextController )
            {
                if(playercontroller(c)!=none && c.PlayerReplicationInfo.team != None && c.PlayerReplicationInfo.team.TeamIndex==myteam)
                    playercontroller(c).ReceiveLocalizedMessage(class'TaskForces.TFConstructedMsg',,,,self);
            }

            //SCORE************************
            pawn(owner).PlayerReplicationInfo.Score+=(tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1])/200;
            tfpri(pawn(owner).PlayerReplicationInfo).AddSkill((tfgri(level.Game.GameReplicationInfo).buildcost[nameindex-1])/20);
        }

        gotostate('Ready');
        PlaySound(sound'TFMedia.tfStationWon',,256);
        spawn(class'TaskForces.TFFlash');

        dmgFX=spawn(class'TaskForces.TFDamageSparks',self);
        dmgFX.SetDrawscale(teamflareDS);
        dmgFX.mPosDev*=teamflareDS*0.8;

        if(!isNotFresh) health=maxhealth;
    }
}

state Ready
{
    function BeginState()
    {
        PlaySound(sound'TFMedia.tfStationWon',,256);
        AmbientSound=default.ambientsound;
        bCollideWorld=true;
        bBlockActors=True;
        bBlockPlayers=true;
    }
}

simulated singular function Touch(Actor Other)
{
	local actor HitActor;
	local vector HitLocation, HitNormal, VelDir;
	local bool bBeyondOther;
	local float BackDist, DirZ;

	//Shamelessly stolen from the code of "Overload"

    if ( Other == None ) return;
    else if ( Grenade(Other) != None )
    {
	    bBeyondOther = ( (Other.Velocity dot (Other.Location - Location)) > 0 );
	    VelDir = Normal(Other.Velocity);
	    DirZ = sqrt(abs(VelDir.Z));
	    BackDist = CollisionRadius * (1 - DirZ) + CollisionHeight * DirZ;
	    if ( bBeyondOther )
		    BackDist += VSize(Other.Location - Location);
	    else
		    BackDist -= VSize(Other.Location - Location);

	    HitActor = Trace(HitLocation, HitNormal, Other.Location, Other.Location - 1.1 * BackDist * VelDir, true);

	    if (HitActor != Other && bBeyondOther)
		    HitLocation = Location - CollisionRadius * VelDir;
    	else if (HitActor != Other && !bBeyondOther)
		    HitLocation = Other.Location;

	    Grenade(Other).Explode(HitLocation, Normal(HitLocation-Other.Location));
    }
    else if ( BioGlob(Other) != None )
    {
	    BioGlob(Other).BlowUp(Other.Location);
    }
}

function bool TellBotHowToDisable(Bot B)
{
    if ( B.Pawn.Weapon.bMeleeWeapon )
    {
	    B.SwitchToBestWeapon();
	    return false;
    }
    else if ( !B.CanAttack(self) )
    {
        return B.Squad.FindPathToObjective(B,self);
    }
    else
    {
	    B.GoalString = "Attacking Enemy Station";
	    B.DoRangedAttackOn(self);
	    return true;
    }
    return false;
}

defaultproperties
{
     BuildTime=30.000000
     chunkcount=4
     ExplosionSound(0)=Sound'TFMedia.Buildings.tfBuildingExp1'
     ExplosionSound(1)=Sound'TFMedia.Buildings.tfBuildingExp2'
     ExplosionSound(2)=Sound'TFMedia.Buildings.tfBuildingExp3'
     Chunks(0)=Class'taskforces.TFChunk1x'
     Chunks(1)=Class'taskforces.TFChunk2x'
     Chunks(2)=Class'taskforces.TFChunk3x'
     Chunks(3)=Class'taskforces.TFChunk4x'
     BuildingName="Building"
     teamflareDS=1.000000
     HitSounds(0)=Sound'TFMedia.Buildings.tfStationHit1'
     HitSounds(1)=Sound'TFMedia.Buildings.tfStationHit2'
     HitSounds(2)=Sound'TFMedia.Buildings.tfStationHit3'
     DestructionMessage=""
     ObjectiveStringSuffix=" Station"
     DrawType=DT_StaticMesh
     bStatic=False
     bHidden=False
     bNoDelete=False
     bDynamicLight=True
     bAcceptsProjectors=False
     bIgnoreEncroachers=True
     bAlwaysRelevant=True
     bReplicateMovement=True
     AmbientGlow=10
     bGameRelevant=True
     bCollideWhenPlacing=False
     bCanBeDamaged=True
     bFullVolume=True
     SoundVolume=96
     SoundRadius=192.000000
     TransientSoundVolume=0.200000
     TransientSoundRadius=128.000000
     bCollideActors=True
     bProjTarget=True
     bBlockKarma=True
     bNetNotify=True
     bNetInitial=True
     bPathColliding=True
}
